package com.szholly.utils.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class FunctionUtils {
	
	/**
	 * �ж����Ƿ�����.<br>
	 * ����,�಻���ǳ����,���,�����ʵ�ֺ���ӿ�
	 * 
	 * @param c
	 *            ��
	 * @return �Ƿ��Ǻ�����
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static boolean isFunction(Class<?> c,   Class interfaceClass) {
		if (c == null) {
			return false;
		}
		if (c.isInterface()) {
			return false;
		}
		if (Modifier.isAbstract(c.getModifiers())) {
			return false;// ����
		}
		return interfaceClass.isAssignableFrom(c);
	}
	
	/**
	 * ��ȡ��Ŀ��path�����е��ļ��к��ļ�
	 * 
	 * @return �ļ��б�
	 */
	private static List<File> listPaths() {
		List<File> files = new ArrayList<File>();
		String jars = System.getProperty("java.class.path");
		if (jars == null) {
			System.err.println("java.class.path is null!");
			return files;
		}
		URL root = FunctionUtils.class.getClassLoader().getResource("");
		if (root == null) {
			System.err.println("path root is null!");
			return files;
		}
		String path = null;
		try {
			path = URLDecoder.decode(root.getFile(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return files;
		}
		File dir = new File(path);
		String[] array = (jars).split(";");
		if (array != null) {
			for (String s : array) {
				if (s == null) {
					continue;
				}
				File f = new File(s);
				if (f.exists()) {
					files.add(f);
				} else {//��Щjar����ϵͳĿ¼��,ʡ����·��,Ҫ����
					File jar = new File(dir, s);
					if (jar.exists()) {
						files.add(jar);
					}
				}
			}
		}
		return files;
	}
	
	
	/**
	 * ��ȡ�������еĺ���ʵ����
	 * 
	 * @param pkg
	 *            ����,�˴�ֻ��Ϊ���޶�,��ֹ����Ŀ�ĵĲ���.��������Ҳ����,��Ҫÿ�ҵ�һ�����Ҫ����һ���ж���
	 * @return ���б�
	 */
	@SuppressWarnings({ "rawtypes", "unused" })
	private static List<Class<?>> getClasses(String pkg,Class interfaceClass) {
		List<Class<?>> list = new ArrayList<Class<?>>();
		for (File f : FunctionUtils.listPaths()) {
			// ��������ļ�����ʽ�����ڷ�������
			if (f.isDirectory()) {
				// ��ȡ�������·��
				String path = pkg.replace('.', File.separatorChar);
				FunctionUtils.dirWalker(path, f, list,interfaceClass);
			} else {//�����Ƿ���jar�ļ�
				// ��ȡjar
				JarFile jar = null;
				try {
					jar = new JarFile(f);
				} catch (IOException e) {
					// �п��ܲ���һ��jar
				}
				if (jar == null) {
					continue;
				}
				String path = pkg.replace('.', '/');
				// �Ӵ�jar�� �õ�һ��ö����
				Enumeration<JarEntry> entries = jar.entries();
				// ͬ��Ľ���ѭ�����
				while (entries.hasMoreElements()) {
					// ��ȡjar���һ��ʵ�� ������Ŀ¼ ��һЩjar����������ļ� ��META-INF���ļ�
					JarEntry entry = entries.nextElement();
					String name = entry.getName();
					// �������/��ͷ��
					if (name.charAt(0) == '/') {
						// ��ȡ������ַ�
						name = name.substring(1);
					}
					// ���ǰ�벿�ֺͶ���İ�����ͬ
					if (name.contains(path)) {
						if (name.endsWith(".class") && !entry.isDirectory()) {
							name = name.replace("/", ".").substring(0,
									name.lastIndexOf("."));
							try {
								Class<?> c = Class.forName(name);
								if (FunctionUtils.isFunction(c,interfaceClass)) {
									list.add(c);
								}
							} catch (Exception e) {
								// �Ҳ�������ν��
							}
						}
					}
				}
			}
		}
		return list;
	}
	
	/**
	 * �����ļ��������е���
	 * 
	 * @param path
	 *            ��·��
	 * @param file
	 *            �ļ�
	 * @param list
	 *            �������б�
	 */
	@SuppressWarnings("rawtypes")
	private static void dirWalker(String path, File file, List<Class<?>> list,  Class interfaceClass) {
		if (file.exists()) {
			if (file.isDirectory()) {
				for (File f : file.listFiles()) {
					FunctionUtils.dirWalker(path, f, list,interfaceClass);
				}
			} else {
				Class<?> c = FunctionUtils.loadClassByFile(path, file,interfaceClass);
				if (c != null) {
					list.add(c);
				}
			}
		}
	}
	
	/**
	 * ���ļ�������
	 * 
	 * @param pkg
	 *            ��·��
	 * @param file
	 *            �ļ�
	 * @return �����null
	 */
	@SuppressWarnings("rawtypes")
	private static Class<?> loadClassByFile(String pkg, File file, Class interfaceClass) {
		if (!file.isFile()) {
			return null;
		}
		String name = file.getName();
		if (name.endsWith(".class")) {
			String ap = file.getAbsolutePath();
			if (!ap.contains(pkg)) {
				return null;
			}
			name = ap.substring(ap.indexOf(pkg) + pkg.length());
			if (name.startsWith(File.separator)) {
				name = name.substring(1);
			}
			String path = (pkg + "." + name.substring(0, name.lastIndexOf(".")))
					.replace(File.separatorChar, '.');
			try {
				Class<?> c = Class.forName(path);
				if (FunctionUtils.isFunction(c,interfaceClass)) {
					return c;
				}
			} catch (ClassNotFoundException e) {
				// do nothing
			}
		}
		return null;
	}
}
